/**
 * 任务队列，每次仅执行指定数量的任务，后续的放到下次 requestAnimationFrame() 再执行，以避免一次执行过多内容导致卡顿
 */
type Task = () => void

export class Queue {
  // batch: 单次抽取多少个任务来执行；执行完一批后，会在下一次 requestAnimationFrame() 再执行下一批
  constructor(readonly batch: number = 100) {}

  protected tasks: Task[] = []

  push(...tasks: Task[]) {
    this.tasks.push(...tasks)
    this.execute()
  }

  protected executing = false
  protected execute() {
    if (this.executing) return
    this.executing = true

    const execute = () => {
      // 执行一批任务
      for (let i = 0; i < this.batch; i++) {
        const task = this.tasks.shift()
        if (task) task()
        else break
      }

      // 如果有后续任务，下一个 loop 再执行；没有的话终止执行，等下次 push 任务再触发
      if (this.tasks.length) {
        requestAnimationFrame(execute)
      } else {
        this.executing = false
      }
    }
    requestAnimationFrame(execute)
  }
}
